from collections.abc import Callable
from contextlib import contextmanager

import lldb

from .common import (
    IsTypeBase,
    SummaryRecognizer,
    SynthRecognizer,
    get_full_name,
)


class Debugger:
    def __init__(self, debugger: lldb.SBDebugger):
        self.d = debugger

    def command(self, cmd: str):
        print(cmd)
        self.d.HandleCommand(cmd)

    @contextmanager
    def category_registrator(self, category: str):
        r = TypeRegistrator(debugger=self, category=category)
        yield r
        r.enable()


class TypeRegistrator:
    def __init__(self, debugger: Debugger, category: str | None):
        self.debugger = debugger
        self._category = category

    def _cmd(self, cmd: str):
        self.debugger.command(cmd=cmd)

    def _category_opt(self) -> str:
        if self._category:
            return f' -w {self._category}'
        else:
            return ''

    def _add_type(self, summary: type[IsTypeBase]):
        rec_func = get_full_name(summary.is_type)
        if issubclass(summary, SummaryRecognizer):
            py_func = get_full_name(summary.summary)
            self._cmd(
                cmd=f'type summary add{self._category_opt()} --python-function {py_func} --recognizer-function {rec_func}',
            )
        if issubclass(summary, SynthRecognizer):
            py_class = get_full_name(summary.synth)
            self._cmd(
                f'type synth add{self._category_opt()} --python-class {py_class} --recognizer-function {rec_func}',
            )

    def add_type(self, *summary: type[IsTypeBase]):
        for sum in summary:
            self._add_type(sum)

    def add_summary(self, type_name: str, expr: str, *, novalue: bool = False, regex: bool = False):
        v = ' -v' if novalue else ''
        x = ' -x' if regex else ''
        self._cmd(f'type summary add{self._category_opt()}{v} -s "{expr}"{x} {type_name}')
    
    def add_func_cmd(self, func: Callable[..., None], name: str | None = None):
        name = name or func.__qualname__
        self._cmd(f'command script add -f {func.__module__}.{func.__qualname__} {name}')

    def enable(self):
        self._cmd(f'type category enable {self._category}')
